#ifndef LFU_LIST_HPP
#define LFU_LIST_HPP

#include <memory>

namespace CachePool
{
    template <typename Key, typename Value>
    class LfuCache;

    // 尾部频率低，头部频率高
    template <typename Key, typename Value>
    class LfuList
    {
        // 需要先声明定义私有，公有接口才能用
    private:
        // 相比LRU定义使用外部类，这里换一种方式使用内部类
        // 内部类可以访问外部类的成员，但外部类还要遵守内部类的访问规则访问内部类成员
        class Node
        {
        public:
            Node() : freq_(1), prev_(nullptr), next_(nullptr) {}
            Node(const Key &key, const Value &value) : key_(key), value_(value), freq_(1), prev_(nullptr), next_(nullptr) {}

            // 友元简化访问
            friend class LfuList<Key, Value>;
            friend class LfuCache<Key, Value>;

        private:
            Key key_;
            Value value_;

            size_t freq_; // 访问频次

            std::shared_ptr<Node> prev_; // 上一结点
            std::shared_ptr<Node> next_;
        };

        using NodePtr = std::shared_ptr<Node>;
        size_t freq_;       // 访问频率
        NodePtr dummyHead_; // 假头结点
        NodePtr dummyTail_; // 假尾结点

    public:
        explicit LfuList(const size_t freq) : freq_(freq)
        {
            this->dummyHead_ = std::make_shared<Node>();
            this->dummyTail_ = std::make_shared<Node>();

            this->dummyHead_->next_ = this->dummyTail_;
            this->dummyTail_->prev_ = this->dummyHead_;
        }

        bool isEmpty() const
        {
            return this->dummyHead_->next_ == this->dummyTail_;
        }

        // 提供结点管理方法
        void addNode(NodePtr node)
        {
            if (!node || !this->dummyHead_ || !this->dummyTail_)
            {
                return;
            }

            node->prev_ = this->dummyTail_->prev_;
            node->next_ = this->dummyTail_;

            this->dummyTail_->prev_->next_ = node; // 这里不能改顺序
            this->dummyTail_->prev_ = node;
        }

        void delNode(NodePtr node)
        {
            if (!node || !this->dummyHead_ || !this->dummyTail_)
            {
                return;
            }

            if (!node->prev_ || !node->next_)
            {
                return;
            }

            node->prev_->next_ = node->next_;
            node->next_->prev_ = node->prev_;

            node->prev_ = nullptr;
            node->next_ = nullptr;
            // 智能指针会处理析构
        }

        NodePtr getFirstNode() const
        {
            return this->dummyHead_->next_;
        }

        friend class LfuCache<Key, Value>;
        // friend class ArcCache<Key, Value>;
    };
} // namespace CachePool

#endif // LFU_LIST_HPP